/*
并发 concurrency

很多人都是冲着go大肆宣扬的高并发而忍不住跃跃欲试，但其实从
源码的解析来看，gorouting只是由官方实现的超级“线程池”而已。
不过话说回来，每个实例4-5KB的栈内存占用和由于实现机制而大幅
减少的创建和销毁开销，是制造go号称的高并发的根本原因。另外，
gorouting的简单易用，也在语言层面上给予了开发者巨大的便利。

并发不是并行：Concurrency is not parallelism
并发主要由时间片来实现“同时”运行，在并行则是直接利用
多核实现多线程的运行，但go可以设置使用核数，以发挥多核计算机
的能力

Channel

channel是gorouting沟通的桥梁，大都是阻塞同步的
通过make创建，close关闭
channel是引用类型
可以使用for range来迭代不断操作channel
可以设置单向或双向通道
可以设置缓存大小，在未被填满前不会发生阻塞

Select

可处理一个或多个channel的发送与接收
同时有多个可用的channel时按随机顺序处理
可用空的select来阻塞main函数
可设置超时

string的格式化
fmt.sprint是string的格式化函数，返回格式化的字符串。
也可以使用bytes.Buffer{},bytes.NewBuffer([]byte{}),bytes.NewBufferString(""),然后toString()
*/
package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func Go() {
	fmt.Println("Go Go!!!")
	time.Sleep(2 * time.Second)
}

func Go1(d chan bool, index int) {
	a := 0
	for i := 0; i < 10000000; i++ {
		a += i
	}
	fmt.Println(index, a)
	if index == 9 {
		d <- true
	}
}

func Go2(d chan bool, index int) {
	a := 0
	for i := 0; i < 10000000; i++ {
		a += i
	}
	fmt.Println(index, a)

	d <- true
}
func Go3(wg *sync.WaitGroup, index int) {
	a := 0
	for i := 0; i < 10000000; i++ {
		a += i
	}
	fmt.Println(index, a)
	wg.Done()
}

func main() {

	fmt.Println("------------------go关键字----------------------")
	go Go()
	go func() {
		fmt.Println("Go Anonymous function!!!")
	}()
	time.Sleep(2 * time.Second)

	fmt.Println("------------------channel make close <- ----------------------")
	a := make(chan bool) //创建channel a
	go func() {
		fmt.Println("Go Go!!!")
		a <- true //向channel中发送数据 bool类型true
		close(a)  //关闭channel a
	}()
	a1 := <-a //用a1阻塞接收channel a中的数据
	fmt.Println(a1)
	<-a //阻塞等待channel a 完成，丢弃channel中的数据
	a2 := <-a
	fmt.Println(a2)

	fmt.Println("------------------channel for range----------------------")
	b := make(chan bool) //创建channel a
	go func() {
		fmt.Println("Go Go!!!")
		b <- true //向channel中发送数据 bool类型true
		close(b)  //关闭channel a
	}()
	for v := range b { //通过for range来迭代channel,当channel被close时，遍历迭代结束
		fmt.Println(v)
	}

	fmt.Println("------------------channel cache----------------------")
	fmt.Println("channel without cache is syn will print Go Go!!!")
	c := make(chan bool) //创建channel a
	go func() {
		fmt.Println("Go Go!!!")
		<-c
		close(c) //关闭channel a
	}()
	c <- true //向channel中发送数据 因为没有缓存是阻塞的，所以等到匿名函数接收数据之后才终止

	fmt.Println("channel with cache will not print Go Go!!!")
	c = make(chan bool, 1) //创建channel a 有缓存
	go func() {
		fmt.Println("Go Go!!!")
		c <- true
		<-c
		close(c) //关闭channel a
	}()
	c <- true //向channel中发送数据，因为有缓存且没有满是不阻塞，所以当main函数终止，匿名函数还没执行就终止
	//	当main函数继续往下执行，匿名函数中的逻辑才有可能被执行到

	fmt.Println("------------------channel runtime.gomaxprocs----------------------")
	fmt.Println("10个Go1函数没有都执行完，就退出了")
	fmt.Println(runtime.GOMAXPROCS(runtime.NumCPU()), runtime.NumCPU()) //设置go使用的cpu核数,并返回之前go默认使用cpu的核数
	d := make(chan bool)
	for i := 0; i < 10; i++ {
		go Go1(d, i)
	}
	<-d

	fmt.Println("------------------using cached channel wait for all gorouting completion by iterate <-channel  ----------------------")
	fmt.Println("等待channel中的10个数据都接收完，才退出，10个Go2函数没有都执行完")
	runtime.GOMAXPROCS(runtime.NumCPU()) //设置go使用的cpu核数,并返回之前go默认使用cpu的核数
	e := make(chan bool, 10)
	for i := 0; i < 10; i++ {
		go Go2(e, i)
	}
	for i := 0; i < 10; i++ {
		<-e
	}

	fmt.Println("------------------using cached channel wait for all gorouting completion by sync.WaitGroup ----------------------")
	fmt.Println("等待channel中的10个数据都接收完，才退出，10个Go3函数没有都执行完")
	runtime.GOMAXPROCS(runtime.NumCPU()) //设置go使用的cpu核数,并返回之前go默认使用cpu的核数
	ewg := sync.WaitGroup{}
	ewg.Add(10)
	for i := 0; i < 10; i++ {
		go Go3(&ewg, i)
	}
	ewg.Wait()

	fmt.Println("------------------select case ----------------------")
	fmt.Println("当一个case的channel关闭时会一直返回channel的默认值，则select会一直读取这个关闭的channel，造成死循环")
	f1, f2 := make(chan int), make(chan string)
	f3 := make(chan bool)
	go func() {
		for {
			select {
			case v, ok := <-f1:
				if !ok {
					f3 <- true
					break
				}
				fmt.Println(v)
			case v, ok := <-f2:
				if !ok {
					f3 <- true
					break
				}
				fmt.Println(v)
			}
		}
	}()

	f1 <- 1
	f2 <- "hi"
	f1 <- 3
	f2 <- "hello"

	close(f1)
	<-f3
	/*
		fmt.Println("------------------select close channel dead loop----------------------")
		i1, i2 := make(chan int), make(chan string)
		i3 := make(chan bool)
		go func() {
			a, b := false, false
			for {
				select {
				case v, ok := <-i1: //i1关闭后，会一直进入该case，其中v==2，ok==false
					if !ok {
						if !a {
							a = true
							i3 <- true

						}
						break
					}
					fmt.Println(v)
				case v, ok := <-i2:
					if !ok {
						if !b {
							b = true
							i3 <- true
						}
						break
					}
					fmt.Println(v)
				}
			}
		}()

		i1 <- 1
		i2 <- "hi"
		i1 <- 3
		i2 <- "hello"

		close(i1)
		for i := 0; i < 2; i++ {
			<-i3 //由于i1关闭，上面select会一直进去读取i1的case，i3中只会写入一个值，所以程序会一直阻塞在读第二个值，造成死循环
		}
	*/
	fmt.Println("------------------select case random----------------------")
	g := make(chan int)
	go func() {
		for v := range g {
			fmt.Println(v)
		}

	}()
	for i := 0; i < 10; i++ {
		select {
		case g <- 0:
		case g <- 1:
		}
	}

	fmt.Println("------------------empty select block main panic----------------------")
	//	select {}

	fmt.Println("------------------select case timeout----------------------")
	h := make(chan bool)
	go func() {
		select {
		case v := <-h:
			fmt.Println(v)
		case <-time.After(time.Second * 1):
			fmt.Println("timeout")
		}
	}()
	//	h <- true
	time.Sleep(time.Second * 2)

	fmt.Println("------------------classroom work----------------------")
	fmt.Println("创建一个 goroutine，与主线程按顺序相互发送信息若干次并打印")
	fmt.Println("------mehtod1")
	j := make(chan string)
	go func() {
		for v := range j {
			fmt.Println(v)
			j <- fmt.Sprint("I got ", v)

		}
	}()
	for i := 0; i < 10; i++ {
		j <- fmt.Sprint("hello ", i)
		fmt.Println(<-j)
	}
	fmt.Println("------mehtod2")
	j1 := make(chan string)
	go func() {
		for {
			v := <-j1
			fmt.Println(v)
			j1 <- fmt.Sprint("I got ", v)
		}
	}()
	for i := 0; i < 10; i++ {
		j1 <- fmt.Sprint("hello ", i)
		fmt.Println(<-j1)
	}

}
